API BlueprintでAPIドキュメントを作成してGitHub、TravisCI、S3で運用する
APIドキュメント作成の経緯
クラスメソッドではモバイルアプリケーションのAPIサーバを作ることが多いのですが、フロントエンド担当者とのやりとりでどうしてもドキュメントが必要になります。今までいろんな形で作ってきたのですがどれも問題がありました。
- フリーフォーマットでWikiに書く。いつの間にか誰も管理しなくなる(できなくなる)。そして誰も見なくなる。
- コードからドキュメント自動生成の方法のみで運用するとAPIのコードを書ける人しか編集できなくなる
- 結局待ち時間が発生する
- フロントの実装者も編集できるようにしたい
- モックサーバのデータとドキュメントを別々に運用していると、どちらかの更新を忘れる
今回、新しくAPIドキュメントを作るにあたり、今までの問題も踏まえ次のようなフローでドキュメント作成、運用をしてみました。
- ドキュメントはマークダウンで記述して、ドキュメントからHTML、開発用のモックサーバを生成する
- 生成したHTMLドキュメントはS3のバケットに置く。S3のWebサイトホスティング機能を使って常に最新版のドキュメントをブラウザで見れるようにする
- ドキュメントの運用はGitHub、変更はプルリクベースで行う運用にする
API Blueprint
APIドキュメント作成ツールを調べていると、実現したいことがAPI Blueprintでできることが分かりました。
API Blueprint
API BlueprintはAPIのドキュメント記述ルールを定義していて、そのルールで作成したドキュメントからHTMLの生成やモックサーバの作成をしてくれる様々なツールが用意されています。
記述ルールはマークダウン拡張です。詳細は公式ページやサンプルを参照してください。
API Blueprintのチュートリアル
マークダウンのサンプルが置いてあるリポジトリ
以下はAPI Blueprintのルールで記述したサンプルです。
FORMAT: 1A # Group Questions ## Question Collection [/questions] ### List All Questions [GET] + Response 200 (application/json) [ { "question": "Favourite programming language?", "published_at": "2014-11-11T08:40:51.620Z", "url": "/questions/1", "choices": [ { "choice": "Swift", "url": "/questions/1/choices/1", "votes": 2048 }, { "choice": "Python", "url": "/questions/1/choices/2", "votes": 1024 }, { "choice": "Objective-C", "url": "/questions/1/choices/3", "votes": 512 }, { "choice": "Ruby", "url": "/questions/1/choices/4", "votes": 256 } ] } ] ### Create a New Question [POST] + question (string) - The question + choices (array[string]) - A collection of choices. + Request (application/json) { "question": "Favourite programming language?", "choices": [ "Swift", "Python", "Objective-C", "Ruby" ] }+ Response 201 (application/json) + Headers Location: /questions/1 + Body { "question": "Favourite programming language?", "published_at": "2014-11-11T08:40:51.620Z", "url": "/questions/1", "choices": [ { "choice": "Swift", "url": "/questions/1/choices/1", "votes": 0 }, { "choice": "Python", "url": "/questions/1/choices/2", "votes": 0 }, { "choice": "Objective-C", "url": "/questions/1/choices/3", "votes": 0 }, { "choice": "Ruby", "url": "/questions/1/choices/4", "votes": 0 } ] } ## Question [/questions/{question_id}] ### Get a Question [GET] + Parameters + id (string) + Response 200 (application/json) { "id": 1 "question": "Favourite programming language?", "published_at": "2014-11-11T08:40:51.620Z", "choices": [ { "choice": "Swift", "url": "/questions/1/choices/1", "votes": 2048 }, { "choice": "Python", "url": "/questions/1/choices/2", "votes": 1024 }, { "choice": "Objective-C", "url": "/questions/1/choices/3", "votes": 512 }, { "choice": "Ruby", "url": "/questions/1/choices/4", "votes": 256 } ] }
マークダウン -> HTML変換
aglioというnodeモジュールを使います
aglio
npm install -g aglio
もしくはpackage.jsonを作成してnpm install
でも良いです。
変換コマンドは
aglio -i input.md output.html
です。うまくレイアウトされたHTMLが生成されます
モックサーバの作成
その名の通り、api-mockというnodeモジュールを使います。
api-mock
npm install -g api-mock
でインストールして、
api-mock hoge.md
とするとモックサーバがローカルに立ち上がります。
試しにAPIをcurlコマンドで呼び出してみましょう。
curl http://localhost:3001/questions/1 { "id": 1 "question": "Favourite programming language?", "published_at": "2014-11-11T08:40:51.620Z", "choices": [ { "choice": "Swift", "url": "/questions/1/choices/1", "votes": 2048 }, { "choice": "Python", "url": "/questions/1/choices/2", "votes": 1024 }, { "choice": "Objective-C", "url": "/questions/1/choices/3", "votes": 512 }, { "choice": "Ruby", "url": "/questions/1/choices/4", "votes": 256 } ] }
ドキュメントに定義したレスポンスが返却されています。
S3への配信
さて、共通ルールに沿ったドキュメントの作成、HTMLへの変換、モックサーバの作成はできました。 後はS3へ配信するだけですが、せっかくなのでCIサーバを使って自動化しましょう。現在のプロジェクトではCIサービスにTravisを使っていますので、Travisを使った次のような仕組みを作ります
- MasterブランチにマージされたタイミングでTravisCIでマークダウンファイルをHTMLに変換する
- 出力したHTMLをS3にアップロード
- S3のWebサイトホスティング機能を使ってメンバーが最新のドキュメントをWebブラウザで確認できるようにする
それではやってみましょう!
.travis.ymlの設定
aglioというnode_moduleを使ってHTMLに変換するので.travis.ymlを以下のように設定しました。aglioコマンドをインストールするために追加でビルド環境を設定する必要があります。
language: node_js node_js: - '4' cache: directories: - node_modules # 時間短縮のため、キャッシュする addons: apt: sources: - ubuntu-toolchain-r-test packages: - gcc-4.8 - g++-4.8 env: CXX="g++-4.8" CC="gcc-4.8" branches: only: - master install: - npm install script: - api/bin/converter.sh # HTML変換コマンドが書かれたシェルをここに指定 deploy: provider: s3 access_key_id: secure: アクセスキー secret_access_key: secure: シークレットアクセスキー bucket: バケット名 skip_cleanup: true acl: public_read endpoint: バケットのURL region: ap-northeast-1 local_dir: api/output # このディレクトリのファイルがS3にアップロードされる
アクセスキーの暗号化
アクセスキーとシークレットアクセスキーはtravisコマンドで暗号化したものを設定します。次のように指定します。
travis encrypt --add deploy.access_key_id 'アクセスキー' travis encrypt --add deploy.secret_access_key 'シークレットアクセスキー'
travisコマンドについては以下を参照してください。
travisコマンドのリポジトリ
Travis上でマークダウンファイルをHTMLに変換
特にローカル環境で実行するコマンドと変わりませんが、一応変換するシェルを書いておきます。
複数のマークダウンファイルを一つにまとめてからHTMLに変換しています。
#!/bin/bash cd `dirname $0` files=() files+=('../hoge-api.md') files+=('../fuga-api.md') echo 'FORMAT: 1A' > ../api-document.md || exit $? cat ${files[@]} | sed -e '/^FORMAT: 1A/d' >> ../api-document.md || exit $? ../../node_modules/.bin/aglio -i ../api-document.md -o ../output/api-document.html || exit $? exit 0
まとめ
ここまでで一連の仕組みづくりができました。APIドキュメントを作成、修正後、マスターブランチにマージすると、生成されたHTMLファイルがS3のバケットに配信されます。
これで常に最新のAPIドキュメントをWebブラウザで確認できるようになりました。
API Blueprintはコードからドキュメントの生成もサポートしているので、次はコードからドキュメントを生成する方法を調査してみたいと思います。